# -*- coding: utf-8 -*-

import pogre

class Style (object):

    def __init__ (self):
        self.font = None
        self.fgcolor = 1.0, 1.0, 1.0, 1.0
        self.bgcolor = None
        self.button = {
            "normal" : {
                "fgcolor" : (1.0, 1.0, 1.0, 1.0),
                "bgcolor" : (0.5, 0.5, 0.5, 1.0)
            },
            "active" : {
                "fgcolor" : (1.0, 1.0, 1.0, 1.0),
                "bgcolor" : (1.0, 0.5, 0.14, 1.0)
            },
            "pressed" : {
                "fgcolor" : (1.0, 1.0, 1.0, 1.0),
                "bgcolor" : (0.92, 0.1, 0.14, 1.0)
            },
            "disabled" : {
                "fgcolor" : (1.0, 1.0, 1.0, 1.0),
                "bgcolor" : (0.7, 0.7, 0.7, 0.8)
            }
        }
        self.editline = {
            "normal" : {
                "fgcolor" : (1.0, 1.0, 1.0, 1.0),
                "bgcolor" : (0.5, 0.5, 0.9, 1.0)
            },
            "active" : {
                "fgcolor" : (1.0, 1.0, 1.0, 1.0),
                "bgcolor" : (1.0, 0.5, 0.14, 1.0)
            },
            "pressed" : {
                "fgcolor" : (1.0, 1.0, 1.0, 1.0),
                "bgcolor" : (0.92, 0.1, 0.14, 1.0)
            }
        }
        self.combobox = {
            "normal" : {
                "fgcolor" : (1.0, 1.0, 1.0, 1.0),
                "bgcolor" : (0.3, 0.7, 0.3, 1.0)
            },
            "active" : {
                "fgcolor" : (1.0, 1.0, 1.0, 1.0),
                "bgcolor" : (1.0, 0.5, 0.14, 1.0)
            },
            "pressed" : {
                "fgcolor" : (1.0, 1.0, 1.0, 1.0),
                "bgcolor" : (0.92, 0.1, 0.14, 1.0)
            }
        }

class Widget (object):

    def __init__ (self, style):
        self.visible = True
        self.disabled = False
        self.position = 0, 0
        self.children = []
        self.parent = None
        self.style = style

    def draw (self):
        if not self.visible: return
        self._draw ()
        for widget in self.children:
            widget.draw ()

    def _draw (self):
        pass

    def abs_disabled (self):
        if self.parent:
            return self.parent.abs_disabled ()
        return self.disabled

    def set_visible (self, value):
        self.visible = value
        # self.state = "normal"

    def abs_position (self):
        if self.parent:
            px, py = self.parent.abs_position ()
            x, y = self.position
            return px + x, py + y
        return self.position

    def attach_to (self, other):
        if self.parent:
            self.parent.children.remove (self)
        self.parent = other
        if other is None: return
        other.children.append (self)

    def handle (self, event):
        if not self.visible or self.abs_disabled (): return
        if self._handle (event): return
        for widget in self.children:
            if widget.handle (event): return

    def _handle (self, event):
        return False

    def __str__ (self):
        return "{%s position:%s}" % (self.__class__.__name__, str(self.position))
    

class Label (Widget):

    def __init__ (self, style):
        Widget.__init__ (self, style)
        self.text = ""
        self.lines = []

    def set_text (self, text):
        if text == self.text:
            return
        if self.lines:
            for image in self.lines:
                pogre.delete_image (image)
            self.lines = []
        self.text = text
        if text:
            for line in text.split ("\n"):
                if not line: continue
                image = pogre.render_text (self.style.font, line)
                self.lines.insert (0, image)

    def _draw (self):
        if not self.text: return
        offset = 0
        x, y = self.abs_position ()
        if self.style.bgcolor:
            w, h = self.size ()
            pogre.render_color4f (*self.style.bgcolor)
            pogre.draw_rect (x, y, w, h)
        pogre.render_color4f (*self.style.fgcolor)
        for image in self.lines:
            pogre.draw (image, x, y + offset)
            offset += pogre.height_of (image)

    def height (self):
        result = 0
        for image in self.lines:
            result += pogre.height_of (image)
        return result

    def width (self):
        result = 0
        for image in self.lines:
            w = pogre.width_of (image)
            if w > result:
                result = w
        return result

    def size (self):
        return self.width (), self.height ()

class LogLabel (Label):

    def __init__(self, style, max_lines = 5):
        Label.__init__ (self, style)
        self.max_lines = max_lines
        self.dirty = False

    def set_text (self, text):
        if text == self.text:
            return
        self.dirty = True
        self.text = text

    def _render (self):
        if self.lines:
            for image in self.lines:
                pogre.delete_image (image)
            self.lines = []
        if self.text:
            for line in self.text.split ("\n"):
                if line:
                    image = pogre.render_text (self.style.font, line)
                    self.lines.insert (0, image)
        self.dirty = False

    def append_line (self, text):
        lines = self.text.split ("\n")
        if len (lines) > self.max_lines-1:
            lines.pop (0)
        lines.append (text)
        text = "\n".join (lines)
        self.set_text (text)

    def append (self, text):
        for line in text.split ("\n"):
            self.append_line (line)

    def _draw (self):
        if self.dirty: self._render ()
        Label._draw (self)

class ComboBox (Widget):

    def __init__ (self, style):
        Widget.__init__ (self, style)
        self.state = "normal"
        self.size = 0, 0
        self.head = Label (style)
        self.head.attach_to (self)
        self.tail = Widget (style)
        self.tail.attach_to (self)
        self.tail.visible = False
        self.index = 0
        self.items = []

    def set_item (self, index):
        item = self.items [index]
        self.head.set_text (item.text)
        h = self.head.height ()
        sw, sh = self.size
        h = (sh - h) / 2
        self.head.position = h, h

    def set_visible (self, value):
        self.visible = value
        self.state = "normal"

    def append_item (self, text):
        label = Label (self.style)
        label.set_text (text)
        w, h = self.size
        label.position = 0, -h - len (self.items) * h
        label.attach_to (self.tail)
        self.items.append (label)

    def _handle (self, event):
        method = self.__getattribute__(self.state)
        return method (event)

    def normal (self, event):
        self.tail.visible = False
        w, h = self.size
        x, y = self.abs_position ()
        if event == pogre.MOUSE_MOTION:
            mx, my = pogre.mouse_position ()
            if x < mx < x + w and y < my < y + h:
                self.state = "active"
        return False

    def active (self, event):
        self.tail.visible = False
        w, h = self.size
        x, y = self.abs_position ()
        if event == pogre.MOUSE_MOTION:
            mx, my = pogre.mouse_position ()
            if not (x < mx < x + w and y < my < y + h):
                self.state = "normal"
        elif event == pogre.MOUSE_BUTTON_DOWN:
            button = pogre.event_button ()
            if button == pogre.MOUSE_BUTTON_LEFT:
                self.state = "pressed"
                return True
        return False

    def pressed (self, event):
        self.tail.visible = True
        w, h = self.size
        x, y = self.abs_position ()
        y = y - h * len (self.items)
        h = h + h * len (self.items)

        mx, my = pogre.mouse_position ()
        if event == pogre.MOUSE_MOTION:
            mx, my = pogre.mouse_position ()
            if not (x < mx < x + w and y < my < y + h):
                self.state = "normal"
            else:
                x, y = self.abs_position ()
                mx, my = pogre.mouse_position ()
                w, h = self.size
                self.index = (y - my) / h
        elif event == pogre.MOUSE_BUTTON_DOWN:
            button = pogre.event_button ()
            if button == pogre.MOUSE_BUTTON_LEFT:
                
                self.set_item (self.index)
                self.state = "normal"
                return True
        return False

    def _draw (self):
        fgcolor = self.style.combobox [self.state]["fgcolor"]
        bgcolor = self.style.combobox [self.state]["bgcolor"]
        x, y = self.abs_position ()
        w, h = self.size
        pogre.render_color4f (*fgcolor)
        pogre.draw_rect (x, y, w, h)
        pogre.render_color4f (*bgcolor)
        pogre.draw_rect (x+1, y+1, w-2, h-2)
        if self.tail.visible:
            cy = len (self.items) * h
            ty = y - cy
            pogre.render_color4f (0.4, 0.4, 0.4, 1.0)
            pogre.draw_rect (x, ty, w, cy)
            x, y = self.abs_position ()
            y -= h * self.index + h
            bgcolor = self.style.combobox ["active"]["bgcolor"]
            pogre.render_color4f (*bgcolor)
            pogre.draw_rect (x, y, w, h)
        
class Button (Widget):

    def __init__ (self, style):
        Widget.__init__ (self, style)
        self.state = "normal"
        self.size = 0, 0
        self.label = None
        self.callback = None

    def set_text (self, text):
        if self.label is None:
            self.label = Label (self.style)
            self.label.attach_to (self)
        self.label.set_text (text)
        bw, bh = self.size
        w, h = self.label.size ()
        x = (bw - w) / 2
        y = (bh - h) / 2
        self.label.position = x, y

    def set_visible (self, value):
        self.visible = value
        self.state = "normal"

    def _draw (self):
        fgcolor = self.style.button [self.state]["fgcolor"]
        bgcolor = self.style.button [self.state]["bgcolor"]
        x, y = self.abs_position ()
        w, h = self.size
        pogre.render_color4f (*fgcolor)
        pogre.draw_rect (x, y, w, h)
        pogre.render_color4f (*bgcolor)
        pogre.draw_rect (x+1, y+1, w-2, h-2)

    def _handle (self, event):
        method = self.__getattribute__(self.state)
        return method (event)

    def normal (self, event):
        w, h = self.size
        x, y = self.abs_position ()
        if event == pogre.MOUSE_MOTION:
            mx, my = pogre.mouse_position ()
            if x < mx < x + w and y < my < y + h:
                self.state = "active"
        return False
    
    def active (self, event):
        w, h = self.size
        x, y = self.abs_position ()
        if event == pogre.MOUSE_MOTION:
            mx, my = pogre.mouse_position ()
            if not (x < mx < x + w and y < my < y + h):
                self.state = "normal"
        elif event == pogre.MOUSE_BUTTON_DOWN:
            button = pogre.event_button ()
            if button == pogre.MOUSE_BUTTON_LEFT:
                self.state = "pressed"
                if self.callback:
                    self.callback (self)
                return True
        return False

    def pressed (self, event):
        w, h = self.size
        x, y = self.abs_position ()
        if event == pogre.MOUSE_MOTION:
            mx, my = pogre.mouse_position ()
            if not (x < mx < x + w and y < my < y + h):
                self.state = "normal"
        elif event == pogre.MOUSE_BUTTON_UP:
            button = pogre.event_button ()
            if button == pogre.MOUSE_BUTTON_LEFT:
                self.state = "active"
                return True
        return False

class EditLine (Widget):

    def __init__ (self, style):
        Widget.__init__ (self, style)
        self.state = "normal"
        self.size = 100, 20
        self.label = None

    def _handle (self, event):
        method = self.__getattribute__(self.state)
        return method (event)

    def set_visible (self, value):
        self.visible = value
        self.state = "normal"

    def set_text (self, text):
        if self.label is None:
            self.label = Label (self.style)
            self.label.attach_to (self)
        self.label.set_text (text)
        bw, bh = self.size
        w, h = self.label.size ()
        #x = (bw - w) / 2
        y = (bh - h) / 2
        x = y
        self.label.position = x, y

    def get_text (self):
        if self.label is None:
            return ""
        return self.label.text

    def normal (self, event):
        w, h = self.size
        x, y = self.abs_position ()
        if event == pogre.MOUSE_MOTION:
            mx, my = pogre.mouse_position ()
            if x < mx < x + w and y < my < y + h:
                self.state = "active"
        return False

    def active (self, event):
        w, h = self.size
        x, y = self.abs_position ()
        if event == pogre.MOUSE_MOTION:
            mx, my = pogre.mouse_position ()
            if not (x < mx < x + w and y < my < y + h):
                self.state = "normal"
        elif event == pogre.MOUSE_BUTTON_DOWN:
            button = pogre.event_button ()
            if button == pogre.MOUSE_BUTTON_LEFT:
                self.state = "pressed"
                return True
        return False

    def pressed (self, event):
        w, h = self.size
        x, y = self.abs_position ()
        if event == pogre.MOUSE_BUTTON_DOWN:
            button = pogre.event_button ()
            if button == pogre.MOUSE_BUTTON_LEFT:
                mx, my = pogre.mouse_position ()
                if not (x < mx < x + w and y < my < y + h):
                    self.state = "normal"
                else:
                    return True
        elif event == pogre.KEY_DOWN:
            key = pogre.event_keycode ()
            if key == pogre.KC_ESCAPE:
                self.state = "normal"
                return True
            elif key == pogre.KC_RETURN:
                return True
            elif key == pogre.KC_BACKSPACE:
                text = self.get_text ()
                if len(text) > 0:
                    text = text.decode ("utf-8") [:-1]
                    text = text.encode ("utf-8")
                    self.set_text (text)
                return True
            elif key == pogre.KC_TAB:
                return True
            uni = self.get_char ()
            if uni:
                self.set_text (self.get_text () + uni)
                return True
        return False

    def _draw (self):
        fgcolor = self.style.editline [self.state]["fgcolor"]
        bgcolor = self.style.editline [self.state]["bgcolor"]
        x, y = self.abs_position ()
        w, h = self.size
        pogre.render_color4f (*fgcolor)
        pogre.draw_rect (x, y, w, h)
        pogre.render_color4f (*bgcolor)
        pogre.draw_rect (x+1, y+1, w-2, h-2)
        if self.state == "pressed" and self.label:
            w = self.label.width ()
            h = self.label.height ()
            lx, ly = self.label.position
            pogre.render_color4f (*fgcolor)
            pogre.draw_rect (x+lx+w, y+ly, 1, h)

    def get_char (self):
        uni = unichr(pogre.event_unicode ()).encode ("utf-8")
        if uni == "\x00":
            return ""
        return uni